package cn.agrael.struts.plugin.ejb3;

import static cn.agrael.struts.plugin.ejb3.StrutsEJBPluginConstant.ACTION_PROXY_INTERFACES;
import static cn.agrael.struts.plugin.ejb3.StrutsEJBPluginConstant.ENC_PATH;
import static cn.agrael.struts.plugin.ejb3.StrutsEJBPluginConstant.INTERCEPTOR_INTERFACES;
import static cn.agrael.struts.plugin.ejb3.StrutsEJBPluginConstant.IS_PARSE_EJB_ANNOTATION;
import static cn.agrael.struts.plugin.ejb3.StrutsEJBPluginConstant.IS_PARSE_RESOURCE_ANNOTATION;
import static cn.agrael.struts.plugin.ejb3.StrutsEJBPluginConstant.LOCAL;
import static cn.agrael.struts.plugin.ejb3.StrutsEJBPluginConstant.REMOTE;
import static com.opensymphony.xwork2.inject.util.ReferenceType.SOFT;
import static com.opensymphony.xwork2.inject.util.ReferenceType.STRONG;
import static com.opensymphony.xwork2.inject.util.ReferenceType.WEAK;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import javax.ejb.EJB;
import javax.ejb.Local;
import javax.ejb.Remote;
import javax.interceptor.AroundInvoke;
import javax.interceptor.ExcludeClassInterceptors;
import javax.interceptor.ExcludeDefaultInterceptors;
import javax.interceptor.Interceptors;
import javax.interceptor.InvocationContext;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import cn.agrael.struts.plugin.ejb3.annotation.EJBComponent;
import cn.agrael.struts.plugin.ejb3.annotation.ResourceComponent;
import cn.agrael.util.ObjectUtils;

import com.opensymphony.xwork2.ActionProxy;
import com.opensymphony.xwork2.inject.util.ReferenceMap;
import com.opensymphony.xwork2.interceptor.Interceptor;

/**
 * struts 与 EJB 整合的相关工具。
 * 
 * @author <a href="mailto:agraellee@gmail.com">Agrael·Lee</a>
 * 
 */
public class StrutsEJBUtils {

	/** 以完全类名为 key 的 BeanEJBAnnotation 缓存 */
	private static final ReferenceMap<String, BeanEJBAnnotation> BEAN_EJB_ANNOTATION_CACHE = new ReferenceMap<String, BeanEJBAnnotation>(
			STRONG, SOFT);

	/** 以完全类名为 key 的 Action公开方法 缓存 */
	private static final ReferenceMap<Class<?>, Set<String>> ACTION_PUBLIC_METHODS_CACHE = new ReferenceMap<Class<?>, Set<String>>(WEAK,
			STRONG);

	private StrutsEJBUtils() {
	}

	/**
	 * 得到一个类缓存中的 BeanEJBAnnotation。
	 * 
	 * @param beanName 完全类名。
	 * @return beanName 在 缓存中的 BeanEJBAnnotation ，如果不存在则返回 null。
	 */
	public static BeanEJBAnnotation getBeanEJBAnnotation(String beanName) {
		return BEAN_EJB_ANNOTATION_CACHE.get(beanName);
	}

	/**
	 * 得到 bean 实例的类在缓存中的 BeanEJBAnnotation。
	 * 
	 * @param bean 要得到缓存中的 BeanEJBAnnotation 的bean实例。
	 * @return bean 实例的类 缓存中的 BeanEJBAnnotation ，如果不存在则返回 null。
	 * @see #getBeanEJBAnnotation(String)
	 */
	public static BeanEJBAnnotation getBeanEJBAnnotation(Object bean) {
		if (bean == null) {
			return null;
		}
		return getBeanEJBAnnotation(bean.getClass().getName());
	}

	/**
	 * 查看缓存中是否存在 beanName 对应的BeanEJBAnnotation。
	 * 
	 * @param beanName 完全类名。
	 * @return 存在返回 true ，不存在返回 false。
	 */
	public static boolean hasBeanEJBAnnotation(String beanName) {
		return BEAN_EJB_ANNOTATION_CACHE.containsKey(beanName);
	}

	/**
	 * 查看缓存中是否存在 bean 实例的类 对应的BeanEJBAnnotation。
	 * 
	 * @param bean 要得查看缓存中是否存在 BeanEJBAnnotation 的bean实例。
	 * @return 存在返回 true ，不存在返回 false。
	 */
	public static boolean hasBeanEJBAnnotation(Object bean) {
		if (bean == null) {
			return false;
		}
		return hasBeanEJBAnnotation(bean.getClass().getName());
	}

	/**
	 * 解析 bean 的 EJB 注解并返回 bean 的 EJB 注解信息。
	 * 
	 * @param bean 需要解析注解的对象。
	 * @return bean 的 EJB 注解信息。
	 * @throws Exception 发生任何异常时。
	 */
	public static BeanEJBAnnotation parseBeanEJBAnnotation(Object bean) throws Exception {
		if (bean == null) {
			return null;
		}
		Class<?> clazz = bean.getClass();
		String className = clazz.getName();
		BeanEJBAnnotation beanEJBAnnotation = BEAN_EJB_ANNOTATION_CACHE.get(className);
		if (beanEJBAnnotation == null) {
			synchronized (BEAN_EJB_ANNOTATION_CACHE) {
				if ((beanEJBAnnotation = BEAN_EJB_ANNOTATION_CACHE.get(className)) == null) {
					beanEJBAnnotation = new BeanEJBAnnotation();
					// 类注解
					boolean isKeep = false;
					for (Annotation annotation : clazz.getAnnotations()) {
						if (!isKeep && annotation instanceof Resource) {
							beanEJBAnnotation.setClassInject(new ClassInjectAnnotationWrapper(annotation));
							isKeep = true;
						}
						if (!isKeep && annotation instanceof EJB) {
							beanEJBAnnotation.setClassInject(new ClassInjectAnnotationWrapper(annotation));
							isKeep = true;
						}
						if (!isKeep && annotation.getClass().isAnnotationPresent(ResourceComponent.class)) {
							beanEJBAnnotation.setClassInject(new ClassInjectAnnotationWrapper(annotation));
							isKeep = true;
						}
						if (!isKeep && annotation.getClass().isAnnotationPresent(EJBComponent.class)) {
							beanEJBAnnotation.setClassInject(new ClassInjectAnnotationWrapper(annotation));
							isKeep = true;
						}
						if (annotation instanceof Interceptors) {
							InterceptorsAnnotationWrapper interceptorsAnnotationWrapper = new InterceptorsAnnotationWrapper();
							Interceptors interceptorsAnnotation = (Interceptors) annotation;
							Class<?>[] interceptorClasses = interceptorsAnnotation.value();
							InterceptorsAnnotationEntry[] interceptors = new InterceptorsAnnotationEntry[interceptorClasses.length];
							for (int i = 0; i < interceptors.length; i++) {
								interceptors[i] = new InterceptorsAnnotationEntry(ObjectUtils.createObject(interceptorClasses[i]),
										findInterceptorMethod(interceptorClasses[i]));
							}
							interceptorsAnnotationWrapper.setInterceptors(interceptors);
							if (clazz.isAnnotationPresent(ExcludeDefaultInterceptors.class)) {
								// 排除默认拦截
								interceptorsAnnotationWrapper.setExcludeDefaultInterceptors(true);
							}
							beanEJBAnnotation.setClassInterceptors(interceptorsAnnotationWrapper);
						}
					}
					// 字段注解
					Field[] fields = ObjectUtils.getAllField(clazz);
					for (Field field : fields) {
						for (Annotation annotation : field.getAnnotations()) {
							if (annotation instanceof Resource) {
								beanEJBAnnotation.addFieldInject(field.getName(), new FieldInjectAnnotationWrapper(field, annotation));
								break;
							}
							if (annotation instanceof EJB) {
								beanEJBAnnotation.addFieldInject(field.getName(), new FieldInjectAnnotationWrapper(field, annotation));
								break;
							}
							if (annotation.getClass().isAnnotationPresent(ResourceComponent.class)) {
								beanEJBAnnotation.addFieldInject(field.getName(), new FieldInjectAnnotationWrapper(field, annotation));
								break;
							}
							if (annotation.getClass().isAnnotationPresent(EJBComponent.class)) {
								beanEJBAnnotation.addFieldInject(field.getName(), new FieldInjectAnnotationWrapper(field, annotation));
								break;
							}
						}
					}
					// 方法注解
					Method[] methods = clazz.getMethods();
					for (Method method : methods) {
						String methodName = method.getName();
						isKeep = false;
						for (Annotation annotation : method.getAnnotations()) {
							if (!isKeep && annotation instanceof Resource) {
								beanEJBAnnotation.addMethodInject(methodName, new MethodInjectAnnotationWrapper(method, annotation));
								isKeep = true;
							}
							if (!isKeep && annotation instanceof EJB) {
								beanEJBAnnotation.addMethodInject(methodName, new MethodInjectAnnotationWrapper(method, annotation));
								isKeep = true;
							}
							if (!isKeep && annotation.getClass().isAnnotationPresent(ResourceComponent.class)) {
								beanEJBAnnotation.addMethodInject(methodName, new MethodInjectAnnotationWrapper(method, annotation));
								isKeep = true;
							}
							if (!isKeep && annotation.getClass().isAnnotationPresent(EJBComponent.class)) {
								beanEJBAnnotation.addMethodInject(methodName, new MethodInjectAnnotationWrapper(method, annotation));
								isKeep = true;
							}
							if (annotation instanceof Interceptors) {
								InterceptorsAnnotationWrapper interceptorsAnnotationWrapper = new InterceptorsAnnotationWrapper();
								Interceptors interceptorsAnnotation = (Interceptors) annotation;
								Class<?>[] interceptorClasses = interceptorsAnnotation.value();
								InterceptorsAnnotationEntry[] interceptors = new InterceptorsAnnotationEntry[interceptorClasses.length];
								for (int i = 0; i < interceptors.length; i++) {
									interceptors[i] = new InterceptorsAnnotationEntry(ObjectUtils.createObject(interceptorClasses[i]),
											findInterceptorMethod(interceptorClasses[i]));
								}
								interceptorsAnnotationWrapper.setInterceptors(interceptors);
								if (method.isAnnotationPresent(ExcludeDefaultInterceptors.class)) {
									// 排除默认拦截
									interceptorsAnnotationWrapper.setExcludeDefaultInterceptors(true);
								}
								if (method.isAnnotationPresent(ExcludeClassInterceptors.class)) {
									// 排除类拦截
									interceptorsAnnotationWrapper.setExcludeClassInterceptors(true);
								}
								beanEJBAnnotation.addMethodInterceptor(methodName, interceptorsAnnotationWrapper);
							}
							if (annotation instanceof PostConstruct) {
								// 初始化回调
								beanEJBAnnotation.setPostConstructAnnotationMethod(method);
							}
							if (annotation instanceof PreDestroy) {
								// 清除回调
								beanEJBAnnotation.setPreDestroyAnnotationMethod(method);
							}
						}
					}
					// 加入缓存
					BEAN_EJB_ANNOTATION_CACHE.put(className, beanEJBAnnotation);
				}
			}
		}
		return beanEJBAnnotation;
	}

	/**
	 * 执行EJB注入注解（ {@link EJB} 和 {@link Resource}）。该方法不包含 {@link Interceptors} 和
	 * {@link PreDestroy} 及 {@link PostConstruct}
	 * 这样的生命周期方法的处理。要处理这些注解请使用工具的其他方法。
	 * 
	 * @param bean 要执行 EJB 注入的 bean 实例。
	 * @return bean 对应的 BeanEJBAnnotation 信息。
	 * @throws Exception 发生任何异常。
	 */
	public static BeanEJBAnnotation executeEJBInjectAnnotation(Object bean) throws Exception {
		if (bean == null) {
			return null;
		}
		BeanEJBAnnotation beanEJBAnnotation = parseBeanEJBAnnotation(bean);
		if (beanEJBAnnotation.isEmpty()) {
			return beanEJBAnnotation;
		}
		// 字段注入
		Map<String, FieldInjectAnnotationWrapper> fieldInjectAnnotationWrapper = beanEJBAnnotation.getFieldInjects();
		for (FieldInjectAnnotationWrapper injectAnnotationWrapper : fieldInjectAnnotationWrapper.values()) {
			fieldInject(bean, injectAnnotationWrapper);
		}
		// 方法注入
		Map<String, MethodInjectAnnotationWrapper> methodInjectAnnotationWrapper = beanEJBAnnotation.getMethodInjects();
		for (MethodInjectAnnotationWrapper injectAnnotationWrapper : methodInjectAnnotationWrapper.values()) {
			methodInject(bean, injectAnnotationWrapper);
		}
		return beanEJBAnnotation;
	}

	/**
	 * 创建 {@link Interceptor} 代理。
	 * 
	 * @param interceptor 需要代理的 Interceptor。
	 * @param beanEJBAnnotation interceptor 的 BeanEJBAnnotation。
	 * @return 如果 interceptor 为null 或者 beanEJBAnnotation 为 null 或者
	 *         beanEJBAnnotation 为空，则直接返回 actionProxy ，否则返回创建的代理实例。
	 */
	public static Interceptor createInterceptorsAnnotationProxy(Interceptor interceptor, BeanEJBAnnotation beanEJBAnnotation) {
		if (interceptor == null || beanEJBAnnotation == null || beanEJBAnnotation.isEmpty()) {
			return interceptor;
		}
		return (Interceptor) Proxy.newProxyInstance(
				ObjectUtils.getDefaultClassLoader(),
				INTERCEPTOR_INTERFACES,
				new InterceptorProxyHandler(interceptor, beanEJBAnnotation.getClassInterceptors(), beanEJBAnnotation
						.getMethodInterceptors()));
	}

	/**
	 * 创建 {@link ActionProxy} 代理。
	 * 
	 * @param actionProxy 需要代理的 ActionProxy。
	 * @param beanEJBAnnotation actionProxy 中的 action 的 BeanEJBAnnotation。
	 * @return 如果 actionProxy 为null 或者 beanEJBAnnotation 为 null 或者
	 *         beanEJBAnnotation 为空，则直接返回 actionProxy ，否则返回创建的代理实例。
	 */
	public static ActionProxy createActionAnnotationProxy(ActionProxy actionProxy, BeanEJBAnnotation beanEJBAnnotation) {
		if (actionProxy == null || beanEJBAnnotation == null || beanEJBAnnotation.isEmpty()) {
			return actionProxy;
		}
		return (ActionProxy) Proxy.newProxyInstance(ObjectUtils.getDefaultClassLoader(), ACTION_PROXY_INTERFACES, new ActionProxyHandler(
				actionProxy, beanEJBAnnotation.getClassInterceptors(), beanEJBAnnotation.getMethodInterceptors()));
	}

	/**
	 * 创建 拦截器回调方法的上下文信息。
	 * 
	 * @param target 目标实例。
	 * @param method 调用 Interceptor 的 Bean 类的方法。
	 * @param args 包含传入代理实例上方法调用的参数值的对象数组。
	 * @param methodInterceptorsAnnotationWrapper 当前目标实例与方法的方法级别拦截器注解信息包装器。
	 * @param classInterceptorsAnnotationWrapper 当前目标实例与方法的类级别拦截器注解信息包装器。
	 * @return 对应信息的 拦截器回调方法的上下文信息。
	 * @throws NullPointerException 拦截器包装器中的参数为 null 时。
	 */
	public static InvocationContext createInvocationContext(Object target, Method method, Object[] args,
			InterceptorsAnnotationWrapper methodInterceptorsAnnotationWrapper,
			InterceptorsAnnotationWrapper classInterceptorsAnnotationWrapper) {
		List<InterceptorsAnnotationEntry> interceptors = new ArrayList<InterceptorsAnnotationEntry>(
				classInterceptorsAnnotationWrapper.getInterceptors().length);
		if (methodInterceptorsAnnotationWrapper == null) {
			if (classInterceptorsAnnotationWrapper != null) {
				// 如果没有方法级别拦截器则直接添加类级别拦截器
				Collections.addAll(interceptors, classInterceptorsAnnotationWrapper.getInterceptors());
			}
		} else {
			if (classInterceptorsAnnotationWrapper != null && !methodInterceptorsAnnotationWrapper.isExcludeClassInterceptors()) {
				// 没有排除类级别拦截器则添加上类级别拦截器
				Collections.addAll(interceptors, classInterceptorsAnnotationWrapper.getInterceptors());
			}
			// 添加方法拦截器
			Collections.addAll(interceptors, methodInterceptorsAnnotationWrapper.getInterceptors());
		}
		return new InvocationContextImpl(target, method, interceptors.iterator());
	}

	/**
	 * 字段注解注入。
	 * 
	 * @param bean 需要注入的 bean 实例。
	 * @param fieldInjectAnnotationWrapper 字段级别注入注解包装器。
	 * @throws Exception 发生任何异常。
	 */
	public static void fieldInject(Object bean, FieldInjectAnnotationWrapper fieldInjectAnnotationWrapper) throws Exception {
		if (bean == null) {
			return;
		}
		Object resourceObject = null;
		String jndiPath = fieldInjectAnnotationWrapper.getJndiPath();
		Field field = fieldInjectAnnotationWrapper.getField();
		if (jndiPath == null) {
			Annotation annotation = fieldInjectAnnotationWrapper.getInjectAnnotation();
			if ("true".equals(IS_PARSE_RESOURCE_ANNOTATION) && annotation instanceof Resource) {
				resourceObject = StrutsEJBPluginConstant.EJB_CONTAINER.fieldResourceAnnotationLookup(bean.getClass(),
						fieldInjectAnnotationWrapper);
			} else if ("true".equals(IS_PARSE_EJB_ANNOTATION) && annotation instanceof EJB) {
				resourceObject = StrutsEJBPluginConstant.EJB_CONTAINER.fieldEJBAnnotationLookup(bean.getClass(),
						fieldInjectAnnotationWrapper);
			} else if (annotation.getClass().isAnnotationPresent(ResourceComponent.class)) {
				resourceObject = StrutsEJBPluginConstant.EJB_CONTAINER.fieldResourceComponentAnnotationLookup(bean.getClass(),
						fieldInjectAnnotationWrapper);
			} else if (annotation.getClass().isAnnotationPresent(EJBComponent.class)) {
				resourceObject = StrutsEJBPluginConstant.EJB_CONTAINER.fieldEJBComponentAnnotationLookup(bean.getClass(),
						fieldInjectAnnotationWrapper);
			}
		} else {
			resourceObject = lookup(jndiPath);
		}
		// 注入
		fieldInject(bean, field, resourceObject);
	}

	/**
	 * 查找 clazz 上是 Local 或者 Remote 注解，并返回配置中 Local/Remote 对应的字符串。
	 * 
	 * @param clazz 要查找的 Class。
	 * @return 如果找到 Local/Remote注解 ，则返回配置中 Local/Remote 对应的字符串，如果没有，则返回 null。
	 */
	public static String findLocalOrRemote(Class<?> clazz) {
		// 找寻类注解上的本地/远程注解
		if (clazz.isAnnotationPresent(Local.class)) {
			// 本地接口
			return LOCAL;
		} else if (clazz.isAnnotationPresent(Remote.class)) {
			// 远程接口
			return REMOTE;
		} else {
			// 都不是
			return null;
		}
	}

	private static void fieldInject(Object object, final Field field, Object resourceObject) throws Exception {
		// 注入
		ObjectUtils.fieldSetAccessible(field);
		field.set(object, resourceObject);
	}

	/**
	 * 方法注解注入。
	 * 
	 * @param bean 需要注入的 bean 实例。
	 * @param methodInjectAnnotationWrapper 方法级别注入注解包装器。
	 * @throws Exception 发生任何异常。
	 */
	public static void methodInject(Object bean, MethodInjectAnnotationWrapper methodInjectAnnotationWrapper) throws Exception {
		if (bean == null) {
			return;
		}
		Object resourceObject = null;
		String jndiPath = methodInjectAnnotationWrapper.getJndiPath();
		Method method = methodInjectAnnotationWrapper.getMethod();
		if (jndiPath == null) {
			Annotation annotation = methodInjectAnnotationWrapper.getInjectAnnotation();
			if ("true".equals(IS_PARSE_RESOURCE_ANNOTATION) && annotation instanceof Resource) {
				resourceObject = StrutsEJBPluginConstant.EJB_CONTAINER.methodResourceAnnotationLookup(bean.getClass(),
						methodInjectAnnotationWrapper);
			} else if ("true".equals(IS_PARSE_EJB_ANNOTATION) && annotation instanceof EJB) {
				resourceObject = StrutsEJBPluginConstant.EJB_CONTAINER.methodEJBAnnotationLookup(bean.getClass(),
						methodInjectAnnotationWrapper);
			} else if (annotation.getClass().isAnnotationPresent(ResourceComponent.class)) {
				resourceObject = StrutsEJBPluginConstant.EJB_CONTAINER.methodResourceComponentAnnotationLookup(bean.getClass(),
						methodInjectAnnotationWrapper);
			} else if (annotation.getClass().isAnnotationPresent(EJBComponent.class)) {
				resourceObject = StrutsEJBPluginConstant.EJB_CONTAINER.methodEJBComponentAnnotationLookup(bean.getClass(),
						methodInjectAnnotationWrapper);
			}
		} else {
			resourceObject = lookup(jndiPath);
		}
		// 注入
		methodInject(bean, method, resourceObject);
	}

	private static void methodInject(Object object, final Method method, Object resourceObject) throws Exception {
		// 注入
		ObjectUtils.methodSetAccessible(method);
		method.invoke(object, resourceObject);
	}

	/**
	 * 查找资源。
	 * 
	 * @param name 资源的jndi名。
	 * @return name 对应的资源。
	 * @throws NamingException 如果遇到命名异常。
	 */
	public static Object lookup(String name) throws NamingException {
		Context context = new InitialContext();
		try {
			return context.lookup(name);
		} finally {
			if (context != null) {
				context.close();
			}
		}
	}

	/**
	 * 从ENC上下文开始查找。
	 * 
	 * @param name 相对于 ENC 的资源 jndi 名。
	 * @return 相对于 ENC 的name 对应的资源。
	 * @throws NamingException 如果遇到命名异常。
	 */
	public static Object lookupENC(String name) throws NamingException {
		return lookup(ENC_PATH + name);
	}

	/**
	 * 从一个 Class 中找标注有 {@link AroundInvoke} 的方法。
	 * 
	 * @param interceptorClass 要寻找的 Class 实例。
	 * @return 返回 {@link AroundInvoke} 标注的方法，如过有多个则返回查找到的第一个，如果 interceptorClass
	 *         为 null 则返回 null。
	 * @throws NoSuchMethodException 如果没有找到拦截方法。
	 */
	public static Method findInterceptorMethod(Class<?> interceptorClass) throws NoSuchMethodException {
		if (interceptorClass == null) {
			return null;
		}
		Method[] methods = interceptorClass.getDeclaredMethods();
		for (Method method : methods) {
			if (method.isAnnotationPresent(AroundInvoke.class)) {
				return method;
			}
		}
		throw new NoSuchMethodException("拦截器 [" + interceptorClass.getName() + "] 没有找到拦截方法。");
	}

	/**
	 * 模拟Bean生命周期。
	 * 
	 * @param bean 需要模拟生命周期的 bean 实例。
	 * @param beanEJBAnnotation bean 对应的 BeanEJBAnnotation。
	 * @throws Exception 发生任何异常时。
	 */
	public static void simulation(Object bean, BeanEJBAnnotation beanEJBAnnotation) throws Exception {
		// 初始化回调
		Method postConstructMethod = beanEJBAnnotation.getPostConstructAnnotationMethod();
		Map<String, InterceptorsAnnotationWrapper> methodInterceptors = beanEJBAnnotation.getMethodInterceptors();
		if (postConstructMethod != null) {
			if (methodInterceptors.containsKey(postConstructMethod.getName())) {
				createInvocationContext(bean, postConstructMethod, null,
						beanEJBAnnotation.getMethodInterceptors().get(postConstructMethod.getName()),
						beanEJBAnnotation.getClassInterceptors()).proceed();
			} else {
				postConstructMethod.invoke(bean);
			}
		}
		// TODO 目前不支持 PreDestroy
	}

	/**
	 * 得到 action 所有的公共方法名的 {@link Set} 。
	 * 
	 * @param clazz action 的 {@link Class} 对象。
	 * @return 指定 clazz 的 action 的所有的公共方法名的 {@link Set} 。
	 */
	public static Set<String> getActionPublicMethodNames(Class<?> clazz) {
		Set<String> methodSet = ACTION_PUBLIC_METHODS_CACHE.get(clazz);
		if (methodSet == null) {
			synchronized (ACTION_PUBLIC_METHODS_CACHE) {
				if ((methodSet = ACTION_PUBLIC_METHODS_CACHE.get(clazz)) == null) {
					Method[] methods = clazz.getMethods();
					methodSet = new HashSet<String>();
					for (Method method : methods) {
						methodSet.add(method.getName());
					}
					ACTION_PUBLIC_METHODS_CACHE.put(clazz, methodSet);
				}
			}
		}
		return methodSet;
	}

}